/**
 * Copyright 2020 OPSLI 快速开发平台 https://www.opsli.com
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.opsli.modulars.business.czData.web;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.convert.Convert;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.opsli.api.web.business.czData.CzDataRestApi;
import org.opsli.common.annotation.RequiresPermissionsCus;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.opsli.api.base.result.ResultVo;
import org.opsli.common.annotation.ApiRestController;
import org.opsli.common.annotation.EnableLog;
import org.opsli.core.base.controller.BaseRestController;
import org.opsli.core.persistence.Page;
import org.opsli.core.persistence.querybuilder.QueryBuilder;
import org.opsli.core.persistence.querybuilder.WebQueryBuilder;
import org.opsli.modulars.business.app.web.ZkUtils;
import org.opsli.modulars.business.czData.service.impl.CzDataServiceImpl;
import org.opsli.modulars.business.iot.protocol.ConvertCode;
import org.opsli.modulars.business.iot.protocol.SyncChannelUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;

import org.opsli.modulars.business.czData.entity.CzData;
import org.opsli.api.wrapper.czData.CzDataModel;
import org.opsli.modulars.business.czData.service.ICzDataService;

/**
 * 场站数据 Controller
 *
 * @author zk
 * @date 2022-03-31 14:40:23
 */
@Api(tags = CzDataRestApi.TITLE)
@Slf4j
@ApiRestController("/czData")
public class CzDataRestController extends BaseRestController<CzData, CzDataModel, ICzDataService>
        implements CzDataRestApi {


    /**
     * 场站数据 查一条
     *
     * @param model 模型
     * @return ResultVo
     */
    @ApiOperation(value = "获得单条场站数据", notes = "获得单条场站数据 - ID")
    @RequiresPermissions("czdata_select")
    @Override
    public ResultVo<CzDataModel> get(CzDataModel model) {
        // 如果系统内部调用 则直接查数据库
        if (model != null && model.getIzApi() != null && model.getIzApi()) {
            model = IService.get(model);
        }
        return ResultVo.success(model);
    }

    /**
     * 场站数据 查询分页
     *
     * @param pageNo   当前页
     * @param pageSize 每页条数
     * @param request  request
     * @return ResultVo
     */
    @ApiOperation(value = "获得分页数据", notes = "获得分页数据 - 查询构造器")
    @RequiresPermissions("czdata_select")
    @Override
    public ResultVo<?> findPage(Integer pageNo, Integer pageSize, HttpServletRequest request) {

        QueryBuilder<CzData> queryBuilder = new WebQueryBuilder<>(entityClazz, request.getParameterMap());
        Page<CzData, CzDataModel> page = new Page<>(pageNo, pageSize);
        page.setQueryWrapper(queryBuilder.build());
        page = IService.findPage(page);

        return ResultVo.success(page.getPageData());
    }

    /**
     * 场站数据 新增
     *
     * @param model 模型
     * @return ResultVo
     */
    @ApiOperation(value = "新增场站数据数据", notes = "新增场站数据数据")
    @RequiresPermissions("czdata_insert")
    @EnableLog
    @Override
    public ResultVo<?> insert(CzDataModel model) {
        // 调用新增方法
        IService.insert(model);
        return ResultVo.success("新增场站数据成功");
    }

    /**
     * 场站数据 修改
     *
     * @param model 模型
     * @return ResultVo
     */
    @ApiOperation(value = "修改场站数据数据", notes = "修改场站数据数据")
    @RequiresPermissions("czdata_update")
    @EnableLog
    @Override
    public ResultVo<?> update(CzDataModel model) {
        // 调用修改方法
        IService.update(model);
        return ResultVo.success("修改场站数据成功");
    }


    /**
     * 场站数据 删除
     *
     * @param id ID
     * @return ResultVo
     */
    @ApiOperation(value = "删除场站数据数据", notes = "删除场站数据数据")
    @RequiresPermissions("czdata_update")
    @EnableLog
    @Override
    public ResultVo<?> del(String id) {
        IService.delete(id);
        return ResultVo.success("删除场站数据成功");
    }

    /**
     * 场站数据 批量删除
     *
     * @param ids ID 数组
     * @return ResultVo
     */
    @ApiOperation(value = "批量删除场站数据数据", notes = "批量删除场站数据数据")
    @RequiresPermissions("czdata_update")
    @EnableLog
    @Override
    public ResultVo<?> delAll(String ids) {
        String[] idArray = Convert.toStrArray(ids);
        IService.deleteAll(idArray);
        return ResultVo.success("批量删除场站数据成功");
    }


    /**
     * 场站数据 Excel 导出
     * 注：这里 RequiresPermissionsCus 引入的是 自定义鉴权注解
     * <p>
     * 导出时，Token认证和方法权限认证 全部都由自定义完成
     * 因为在 导出不成功时，需要推送错误信息，
     * 前端直接走下载流，当失败时无法获得失败信息，即使前后端换一种方式后端推送二进制文件前端再次解析也是最少2倍的耗时
     * ，且如果数据量过大，前端进行渲染时直接会把浏览器卡死
     * 而直接开启socket接口推送显然是太过浪费资源了，所以目前采用Java最原始的手段
     * response 推送 javascript代码 alert 提示报错信息
     *
     * @param request  request
     * @param response response
     */
    @ApiOperation(value = "导出Excel", notes = "导出Excel")
    @RequiresPermissionsCus("czdata_export")
    @EnableLog
    @Override
    public void exportExcel(HttpServletRequest request, HttpServletResponse response) {
        // 当前方法
        Method method = ReflectUtil.getMethodByName(this.getClass(), "exportExcel");
        QueryBuilder<CzData> queryBuilder = new WebQueryBuilder<>(entityClazz, request.getParameterMap());
        super.excelExport(CzDataRestApi.SUB_TITLE, queryBuilder.build(), response, method);
    }

    /**
     * 场站数据 Excel 导入
     * 注：这里 RequiresPermissions 引入的是 Shiro原生鉴权注解
     *
     * @param request 文件流 request
     * @return ResultVo
     */
    @ApiOperation(value = "导入Excel", notes = "导入Excel")
    @RequiresPermissions("czdata_import")
    @EnableLog
    @Override
    public ResultVo<?> importExcel(MultipartHttpServletRequest request) {
        return super.importExcel(request);
    }

    /**
     * 场站数据 Excel 下载导入模版
     * 注：这里 RequiresPermissionsCus 引入的是 自定义鉴权注解
     *
     * @param response response
     */
    @ApiOperation(value = "导出Excel模版", notes = "导出Excel模版")
    @RequiresPermissionsCus("czdata_import")
    @Override
    public void importTemplate(HttpServletResponse response) {
        // 当前方法
        Method method = ReflectUtil.getMethodByName(this.getClass(), "importTemplate");
        super.importTemplate(CzDataRestApi.SUB_TITLE, response, method);
    }

    @Autowired
    CzDataServiceImpl czd;

    @GetMapping(value = "/getGateData")
    public List<CzData> getGateSation(HttpServletRequest request, String devid) {
        List l = czd.getGateData(devid);
       /* try {
            Channel channel= SyncChannelUtil.getChannel("002022047005z");
            if(channel!=null&&channel.isActive()){
                //发送校时请求
                byte[] bytes=new byte[4];
                bytes[0]=0x00;
                bytes[1]=0x08;
                bytes[2]=0x00;
                bytes[3]=0x34;
                String s= ConvertCode.bytesToHexString(bytes);
                System.out.println(s);
                String ss=ConvertCode.getCRC3(bytes);
                writeToClient(s+ss,channel,"读场站数据");
            }else{
                System.out.println("场站通道不活跃");
            }
        }catch (Exception e){
        }*/
        return l;
    }

    /**
     * 公用回写数据到客户端的方法
     * @param channel
     * @param mark 用于打印/log的输出
     * <br>//channel.writeAndFlush(msg);//不行
     * <br>//channel.writeAndFlush(receiveStr.getBytes());//不行
     * <br>在netty里，进出的都是ByteBuf，楼主应确定服务端是否有对应的编码器，将字符串转化为ByteBuf
     */
    private void writeToClient(final String receiveStr, Channel channel, final String mark) {
        try {
            ByteBuf bufff = Unpooled.buffer();//netty需要用ByteBuf传输
            bufff.writeBytes(ConvertCode.hexString2Bytes(receiveStr));//对接需要16进制
            channel.writeAndFlush(bufff).addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    StringBuilder sb = new StringBuilder("");
                    if (!ZkUtils.isEmpty(mark)) {
                        sb.append("【").append(mark).append("】");
                    }
                    if (future.isSuccess()) {
                        System.out.println("发送场站数据成功++++++");
                        System.out.println(sb.toString() + "回写成功" + receiveStr);
                    } else {
                        System.out.println(sb.toString() + "回写失败" + receiveStr);

                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("调用通用writeToClient()异常" + e.getMessage());

        }
    }

}
